package cn.kust.chat.service;

import cn.kust.chat.entity.ChatMessage;
import cn.kust.chat.entity.ChatUserBind;
import cn.kust.chat.mapper.ChatMessageMapper;
import cn.kust.chat.mapper.ChatUserBindMapper;
import cn.kust.chat.pojo.*;
import cn.kust.chat.utils.UserChannelRel;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.util.concurrent.GlobalEventExecutor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.CrossOrigin;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.List;

/**
 * 用于处理消息
 * 由于它的传输数据载体是frame，frame在netty中是用于为websocket专门处理文本对象的，frame是消息的载体
 */
@Service
@Slf4j
public class ChatService {

    //用于记录和管理所有客户端的channel
    private static ChannelGroup users = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);

    @Resource
    private ChatUserBindMapper chatUserBindMapper;

    @Resource
    private ChatMessageMapper chatMessageMapper;

    public void dealWithChat(ChannelHandlerContext cxt, String content) throws Exception {
        //获取客户端所传输的消息
        log.info("接收到的数据：{}", content);

        // 判断是否为注册用户
        ConnectIn connectIn = JSON.parseObject(content, ConnectIn.class);
        if (connectIn != null && connectIn.getUserId() != null) {
            //将用户和通道关联起来
            UserChannelRel.put(connectIn.getUserId(), cxt.channel());
            return;
        }


        // 判断消息是否合法
        MsgIn msg = JSON.parseObject(content, MsgIn.class);
        String s = verifyMsg(msg);
        if (s != null) {
            users.writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(new Msg4SendOut(-1, s))));
            return;
        }

        // 保存消息
        // 查询绑定关系
        List<Long> userIds = Arrays.asList(msg.getSendUserId(), msg.getReceiveUserId());
        List<ChatUserBind> binds = chatUserBindMapper.selectList(new LambdaQueryWrapper<ChatUserBind>()
                .in(ChatUserBind::getUserIdOne, userIds).or().in(ChatUserBind::getUserIdTwo, userIds));
        // 没有绑定关系，则插入新关系
        ChatUserBind bind = null;
        if (binds == null || binds.size() < 1) {
            bind = new ChatUserBind();
            bind.setUserIdOne(msg.getSendUserId());
            bind.setUserIdTwo(msg.getReceiveUserId());
            bind.setCreateTime(LocalDateTime.now());
            chatUserBindMapper.insert(bind);
        } else {
            bind = binds.get(0);
        }

        //保存消息
        ChatMessage message = new ChatMessage();
        BeanUtils.copyProperties(msg, message);
        message.setBindId(bind.getBindId());
        message.setCreateTime(LocalDateTime.now());
        chatMessageMapper.insert(message);
        


        //发送消息
        Channel receiveChannel = UserChannelRel.getChannel(msg.getReceiveUserId());
        if (receiveChannel == null) {
            //离线用户
            cxt.writeAndFlush(new TextWebSocketFrame("离线用户"));
        } else {
            //在线用户,发送消息
            receiveChannel.writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(new MsgOut(msg.getMessage(), LocalDateTime.now().format(DateTimeFormatter.ISO_DATE_TIME)))));
        }
    }


    /**
     * 验证消息是否合法
     *
     * @param msg 消息对象
     * @return null-合法，否则表示消息不合法
     */
    private String verifyMsg(MsgIn msg) {
        if (msg == null) {
            return "消息为空";
        }
        if (msg.getSendUserId() == null) {
            return "发送者编号不得为空";
        }
        if (msg.getReceiveUserId() == null) {
            return "接收者编号不得为空";
        }
        if (msg.getMessage() == null) {
            return "消息为空";
        }
        return null;
    }

}
